﻿#include "GraphicsDef.h"

namespace OfUI {

	qreal getAscZValue()
	{
		static qreal zValue = 0;
		zValue += 0.01;
		return zValue;
	}

	double distanceFromPointToLine(const QPointF& point, const QLineF& line)
	{
		if (line.isNull())
			return QLineF(line.p1(), point).length();

		QPointF a = line.p1();
		QPointF b = line.p2();

		double cross = (b.x() - a.x()) * (point.x() - a.x()) + (b.y() - a.y()) * (point.y() - a.y());
		if (cross <= 0)
		{
			return QLineF(a, point).length();
		}
		double ab2 = (b.x() - a.x()) * (b.x() - a.x()) + (b.y() - a.y()) * (b.y() - a.y());

		if (cross >= ab2)
		{
			return QLineF(b, point).length();
		}
		double r = cross / ab2;
		QPointF abCenter = QPointF(a.x() + (b.x() - a.x()) * r, a.y() + (b.y() - a.y()) * r);
		return QLineF(abCenter, point).length();
	}

	QPointF getPointVerticalToLine(const QPointF& point, const QLineF& line)
	{
		if (line.isNull())
			return line.p1();

		QPointF p1 = line.p1();
		QPointF p2 = line.p2();

		// 求直线的一般式方程 Ax + By + C = 0
		double A = p2.y() - p1.y();
		double B = p1.x() - p2.x();
		double C = p2.x() * p1.y() - p1.x() * p2.y();

		// 求直线垂直的直线方程 Bx -Ay + D = 0
		double D = A * point.y() - B * point.x();

		// 垂直点符合两条方程式，可以计算出坐标 x = (-AC-DB) / (AA + BB); y =  (AD - BC) / (AA + BB);
		QPointF crossPoint;
		crossPoint.setX((-A * C - B * D) / (pow(A, 2) + pow(B, 2)));
		crossPoint.setY((A* D - B * C) / (pow(A, 2) + pow(B, 2)));
		return crossPoint;
	}

	QLineF getStraightLineFromObliqueLine(const QLineF& line)
	{
		QPointF sPoint = line.p1();
		QPointF ePoint = line.p2();

		if (qAbs(ePoint.x() - sPoint.x()) > qAbs(ePoint.y() - sPoint.y()))
		{
			ePoint.setY(sPoint.y());
		}
		else
		{
			ePoint.setX(sPoint.x());
		}
		return QLineF(sPoint, ePoint);
	}

	QRectF getSquareFromRect(const QRectF& rect)
	{
		QPointF topLeft = rect.topLeft();
		QPointF botttmRight = rect.bottomRight();
		double dXLen = rect.width();
		double dYLen = rect.height();

		if (qAbs(dXLen) > qAbs(dYLen))
		{
			botttmRight = topLeft + QPointF(qAbs(dYLen) * dXLen / qAbs(dXLen), dYLen);
		}
		else
		{
			botttmRight = topLeft + QPointF(dXLen, qAbs(dXLen) * dYLen / qAbs(dYLen));
		}
		return QRectF(topLeft, botttmRight);
	}

	bool getCircle(const QVector<QPointF>& vPoints, QPointF & center, double & dRadius)
	{
		if (3 != vPoints.count())
			return false;

		// 根据圆上三点计算圆心与半径 https://blog.csdn.net/qq_31073871/article/details/109015969
		double x1 = vPoints.at(0).x();
		double y1 = vPoints.at(0).y();
		double x2 = vPoints.at(1).x();
		double y2 = vPoints.at(1).y();
		double x3 = vPoints.at(2).x();
		double y3 = vPoints.at(2).y();

		// 加快运算速度，避免重复计算，先计算公式中的重复部分
		double x1x1 = x1 * x1;
		double y1y1 = y1 * y1;
		double x2x2 = x2 * x2;
		double y2y2 = y2 * y2;
		double x3x3 = x3 * x3;
		double y3y3 = y3 * y3;

		double x2y3 = x2 * y3;
		double x3y2 = x3 * y2;

		double x2_x3 = x2 - x3;
		double y2_y3 = y2 - y3;

		double x1x1py1y1 = x1x1 + y1y1;
		double x2x2py2y2 = x2x2 + y2y2;
		double x3x3py3y3 = x3x3 + y3y3;

		double A = x1 * y2_y3 - y1 * x2_x3 + x2y3 - x3y2;

		// A = 0 表示三点在一直线上，不能形成圆形
		if (qFuzzyCompare(A, 0))
			return false;

		double B = x1x1py1y1 * (-y2_y3) + x2x2py2y2 * (y1 - y3) + x3x3py3y3 * (y2 - y1);
		double C = x1x1py1y1 * x2_x3 + x2x2py2y2 * (x3 - x1) + x3x3py3y3 * (x1 - x2);
		double D = x1x1py1y1 * (x3y2 - x2y3) + x2x2py2y2 * (x1*y3 - x3 * y1) + x3x3py3y3 * (x2*y1 - x1 * y2);

		center.setX(-B / (2 * A));
		center.setY(-C / (2 * A));
		dRadius = sqrt((B*B + C * C - 4 * A*D) / (4 * A*A));
		return true;
	}

}
